#! /usr/bin/python3 python3
# -*- coding: utf-8 -*-

# *************************************************************
#  Projectname @  pysm
#     Filename @  oss.py.py
#       Author @  Steve.ma
#  Create date @  2018/9/7
#  Description @  
# *************************************************************

import oss2
import requests
import time
import hashlib
import random
from Conf import getConf

class SMOss :
    #基本配置
    AccessKeyId = None
    AccessKeySecret = None
    BucketName = None
    Endpoint = None
    CName = None

    #OSS链接对象
    auth = None
    bucket = None
    service = None

    #Conf 传参
    #强烈建议您不要关闭CRC数据校验功能。如果您关闭此功能，则阿里云不保证上传、下载过程数据的完整性。
    EnableCrc = True
    #设置连接超时时间为30秒。
    ConnectTimeOut = 30

    # InIt 自动执行
    def __init__(self, conf = None):
        #配置可以自己传过来 也可以从Conf中读取
        if conf == None :
            conf = getConf('oss')

        #基本配置
        self.AccessKeyId = conf['AccessKeyId']
        self.AccessKeySecret = conf['AccessKeySecret']
        self.BucketName = conf['BucketName']
        self.Endpoint = conf['Endpoint']

        #额外配置
        if 'CName' in conf :
            self.EnableCrc = conf['CName']
        if 'EnableCrc' in conf :
            self.EnableCrc = conf['EnableCrc']
        if 'ConnectTimeOut' in conf :
            self.ConnectTimeOut = conf['ConnectTimeOut']

        self.conn()
    # 检测权限
    def CheckAuth(self):
        if self.auth == None :
            # 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号。
            self.auth = oss2.Auth(self.AccessKeyId, self.AccessKeySecret)
        return

    #检测存储空间
    def CheckBucket(self, BucketName = None):
        if self.bucket == None :
            if self.CName == None :
                is_cname = False
            else :
                self.Endpoint = self.CName
                is_cname = True
            if BucketName == None :
                BucketName = self.BucketName
            # 自定义域名以my-domain.com为例。is_cname=True为开启CNAME。CNAME是指将自定义域名绑定到存储空间上。
            self.bucket = oss2.Bucket(self.auth, self.Endpoint, BucketName,
                                      is_cname = is_cname,
                                      enable_crc = self.EnableCrc,
                                      connect_timeout = self.ConnectTimeOut)
        return

    # 检测权限和Bucket信息
    def conn(self):
        self.CheckAuth()
        self.CheckBucket()
        return

    # 新建存储空间  type = sub | public
    # 1、只能包括小写字母、数字和短横线（-）。2、必须以小写字母或者数字开头和结尾。3、长度必须在3–63字节之间。
    def newBucket(self, BucketName, type='public'):
        self.CheckAuth()
        if self.CName == None:
            is_cname = False
        else:
            self.Endpoint = self.CName
            is_cname = True
        self.bucket = oss2.Bucket(self.auth, self.Endpoint, BucketName,
                                  is_cname=is_cname,
                                  enable_crc=self.EnableCrc,
                                  connect_timeout=self.ConnectTimeOut)
        if type == 'sub' :
            # 新建存储空间默认为标准存储类型，私有访问权限
            self.bucket.create_bucket()
        elif type == 'public' :
            # 设置存储空间的存储类型为低频访问类型，访问权限为公共读。
            self.bucket.create_bucket(oss2.BUCKET_ACL_PUBLIC_READ, oss2.models.BucketCreateConfig(oss2.BUCKET_STORAGE_CLASS_IA))

    # 删除存储空间
    def delBucket(self, BucketName):
        self.CheckAuth()
        self.CheckBucket(BucketName)
        try:
            # 删除存储空间。
            self.bucket.delete_bucket()
            return True
        except oss2.exceptions.BucketNotEmpty:
            return 'bucket is not empty.'
        except oss2.exceptions.NoSuchBucket:
            return 'bucket does not exist'

    # 获取 Endpoint 下所有的bucket
    def getBucketList(self, Endpoint = None):
        self.CheckAuth()
        if Endpoint == None :
            Endpoint = self.Endpoint
        if self.service == None :
            self.service = oss2.Service(self.auth, Endpoint)
        return [b.name for b in oss2.BucketIterator(self.service)]

    # 获取存储空间相关信息
    def getBucketInfo(self, BucketName):
        self.CheckAuth()
        self.CheckBucket(BucketName)
        # 获取存储空间相关信息
        return self.bucket.get_bucket_info()

        # print('name: ' + bucket_info.name)
        # print('storage class: ' + bucket_info.storage_class)
        # print('creation date: ' + bucket_info.creation_date)
        # print('intranet_endpoint: ' + bucket_info.intranet_endpoint)
        # print('extranet_endpoint ' + bucket_info.extranet_endpoint)
        # print('owner: ' + bucket_info.owner.id)
        # print('grant: ' + bucket_info.acl.grant)

    # 上传 type 默认本地文件 ObjectName 再存储空间地址 file 本地文件路径或者网络路径 content 字符串上传 bytes 上传、unicode 上传的内容
    def upload(self, ObjectName = '', file='', content='',BucketName = None, type='localfile'):
        self.CheckAuth()
        self.CheckBucket(BucketName)
        if type == 'string' :
            result = self.bucket.put_object(ObjectName, content)
        elif type == 'bytes' :
            result = self.bucket.put_object(ObjectName, eval('b"%s"' % content))
        elif type == 'unicode' :
            result = self.bucket.put_object(ObjectName, eval('u"%s"' % content))
        elif type == 'localfile' :
            result = self.bucket.put_object_from_file(ObjectName, file)
        elif type == 'weburl' :
            # requests.get返回的是一个可迭代对象（Iterable），此时Python SDK会通过Chunked Encoding方式上传。
            input = requests.get(file)
            result = self.bucket.put_object(ObjectName, input)

        return {
            # HTTP返回码。
            'httpstatus' : format(result.status),
            # 请求ID。请求ID是请求的唯一标识，强烈建议在程序日志中添加此参数。
            'request_id' : format(result.request_id),
            # ETag是put_object方法返回值特有的属性。
            'ETag' : format(result.etag),
            # HTTP响应头部。
            'date' : format(result.headers['date']),
            # 文件地址
            'url' : self.getFileUrl(ObjectName, BucketName)
        }

    # 获取服务器上的地址
    def getFileUrl(self, ObjectName='', BucketName = None):
        if ObjectName == '' :
            return "Error : ObjectName 必需"
        if self.CName == None :
            if BucketName == None :
                BucketName = self.BucketName
            return 'http://' + BucketName + '.' + self.Endpoint + '/' + ObjectName
        else :
            if self.CName.startswith('http') :
                return self.CName + '/' + ObjectName
            else :
                return 'http://' + self.CName + '/' + ObjectName

    # 生成新的对象名
    def newObjectName(self, FileName = None, folder = None, ext = ''):
        if folder == None :
            folder = self.BucketName
        if FileName == None :
            FileName = self.newFileName(ext)
        return str(folder) + '/' + str(time.strftime('%Y/%m/%d/', time.localtime())) +  FileName

    # 新生成文件名
    def newFileName(self, ext = 'txt'):
        unitime = str(time.time()) + str(random.randrange(10000, 99999))
        return hashlib.md5(eval('b"%s"' % unitime)).hexdigest() + '.' + ext



